﻿using System;
using System.Collections.Generic;
using System.Data;
using EasyLibrary.AR.Classes;
using System.Data.SqlClient;
using System.Globalization;
using System.Threading;
namespace EasyLibrary.AR.Services
{
    public class Gps : ActiveRecord
    {
        public Gps()
        {
        }

        public Gps(int idv, string mat, string refTipo, double lat, double lng, bool lig)
        {
            IdViatura = idv;
            Matricula = mat;

            RefIdTipoViatura = refTipo;
            Latitude = lat;
            Longitude = lng;
            Ligado = lig;
        }

        public Gps(DataRow row)
        {
            IdViatura = (int) row["IDViaturas"];
            Matricula = (string) row["matricula"];
            RefIdTipoViatura = (string) row["TipoViatura"];
            Latitude = (double) row["Latitude"];
            Longitude = (double) row["Longitude"];
            Ligado = (bool) row["LigadoA"];
        }

        public int IdViatura { get; set; }
        public string Matricula { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
        public string RefIdTipoViatura { get; set; }
        public bool Ligado { get; set; }


        public static IList<Gps> GetLocalizacaoActual(int id)
        {
            //     string inIds = string.Join(", ", (from id in ids select id.ToString()).ToArray());
            string sql =
                "SELECT  Viaturas.IDViaturas, Viaturas.matricula, TiposViatura.TipoViatura, Viaturas.Latitude, Viaturas.Longitude, Viaturas.LigadoA FROM            Viaturas INNER JOIN TiposViatura ON Viaturas.RefIDTiposViatura = TiposViatura.IDTiposViatura WHERE (Viaturas.IDViaturas =" +
                id + ")";
            DataSet myDataSet = ExecuteQuery(GetConnection(false), sql);
            if (myDataSet.Tables[0].Rows.Count == 0)
                return null;
            Gps var;
            var ret = new List<Gps>();
            foreach (DataRow row in myDataSet.Tables[0].Rows)
            {
                var = new Gps(row);
                ret.Add(var);
            }

            return ret;
        }

        public IList<GpsCoordinatesSegment> GetCoordinatesSegmentFast(int vehicleId, DateTime from, DateTime to)
        {
            var ret = new List<GpsCoordinatesSegment>();

            Viatura vehicle = new Viatura();
            vehicle.Idviatura = vehicleId;
          //  vehicle = vehicle.getViaturaById(vehicleId);
            var points = GetCoordinatesFromDay(vehicleId, from, to);
            GpsCoordinatesSegment segment=new GpsCoordinatesSegment();
            double percLitro;
            if (vehicle.PercLitr == -1)
                percLitro = 1;
            else percLitro = vehicle.PercLitr;
            if (points != null)
            {
                var state = false;
                var start = 0;
                for (var i = 1; i < points.Count; i++)
                {
                    var prev = points[i - 1];
                    var current = points[i];
                    var next = points[i];

                    if (i < points.Count - 1)
                        next = points[i + 1];

                    if (!prev.On && current.On)// && ((prev.Timestamp.AddMinutes(2) < current.Timestamp) || (start == 0)))
                    {
                        start = i;
                    }


                    if (start == 0)
                    {
                        if (i > 1)
                        {
                            start = 1;
                        }
                    }

                    if (
                        ((start > 0) &&
                        (!current.On && prev.On)) //&& (current.Timestamp.AddMinutes(2) < next.Timestamp)
                        )
                    {

                        state = current.On;
                        var seg = segment.getSegmentFast(points, start, i);
                        if (seg != null)
                        {
                            ret.Add(seg);
                        }
                        start = i;
                    }

                }
                if (start < points.Count)
                {
                   var seg = segment.getSegmentFast(points, start, points.Count);

                   if (seg != null && seg.Distance > 0.2)
                    {
                        ret.Add(seg);
                    }

                }
            }

            return ret;

        }

      

        public IList<GpsCoordinates> GetCoordinatesFromDay(int vehicleId, DateTime from, DateTime to)
        {
            var fromUnix = GetUnixEpoch(from);
            var toUnix = GetUnixEpoch(to);
            
           
           
         
 var myDataSet = executeCommandOnDataSet(string.Format(CultureInfo.InvariantCulture, "SELECT g.IDGeoCodes AS Id, g.RefIDViaturas AS VehicleId, g.RefIDKitStartLogs AS IdStart, v.matricula AS Plate, g.lat AS Latitude, g.lng AS Longitude, g.Data AS Timestamp, g.speed AS Speed, g.course AS Course, g.HDOP AS Accuracy, g.Distancia AS Distancia, g.Address AS Address, g.AddressAccuracy AS AddressAccuracy, g.[On] AS [On], fl.Value AS FuelLevel FROM Viaturas v INNER JOIN GeoCodes g ON g.RefIDViaturas = v.IDViaturas LEFT OUTER JOIN dbo.VehicleData AS fl ON g.IDGeoCodes = fl.IDGeoCodes AND fl.[Function] LIKE 'FuelLevel' WHERE (v.IDViaturas = '{0}') AND (g.Ordem BETWEEN {1} AND {2}) ORDER BY g.Ordem", vehicleId, fromUnix, toUnix));
     

           

            if (myDataSet.Tables[0].Rows.Count == 0)
                return null;

            var ret = new List<GpsCoordinates>(myDataSet.Tables[0].Rows.Count);
            foreach (DataRow row in myDataSet.Tables[0].Rows)
            {
                var point = new GpsCoordinates
                {
                    Id = (int)row["Id"],
                    VehicleId = (int)(long)row["VehicleId"],
                    IdStart = (long)row["IdStart"],
                    Plate = (string)row["Plate"],
                    Latitude = (double)row["Latitude"],
                    Longitude = (double)row["Longitude"],
                    Timestamp = (DateTime)row["Timestamp"],
                    Now = DateTime.Now,
                    Speed = row["Speed"] is DBNull ? 0.0f : (float)(double)row["Speed"],
                    Course = row["Course"] is DBNull ? 0.0f : (float)(double)row["Course"],
                    Accuracy = row["Accuracy"] is DBNull ? 99.9f : (float)(double)row["Accuracy"],
                    Address = row["Address"] is DBNull ? null : (string)row["Address"],
                    AddressAccuracy =
                        row["AddressAccuracy"] is DBNull ? 0 : (int)(short)row["AddressAccuracy"],
                    Distance = row["Distancia"] is DBNull ? 0.0f : (float)(double)row["Distancia"],
                    On = (bool)row["On"],
                    FuelLevel = row["FuelLevel"] is DBNull ? 0 : (double)row["FuelLevel"]
                    //FuelConsumed = row["Consumption"] is DBNull ? 0 : (double) row["Consumption"],
                    //Kms = row["Kms"] is DBNull ? 0 : (double) row["Kms"]

                };
                ret.Add(point);
            }

            return ret;
        }

        public IList<Paragem> getParagensEspec(int vehicleId, DateTime from, DateTime to)
        {
            var ret = new List<Paragem>();
            var points = GetCoordinatesFromDay(vehicleId, from, to);
            Viatura vehicle = new Viatura();
            vehicle.Idviatura = vehicleId;
            GpsCoordinates ini;
            GpsCoordinates fim;
            double maxAnt = 3000;
            double minAnt;
         

            double minut = 4.5;
           

            double percLitro = vehicle.PercLitr == -1 ? 1 : vehicle.PercLitr;
            if (points != null)
            {
                var state = false;
                var start = 0;
                for (var i = 1; i < points.Count; i++)
                {
                    int prevId = i - 1;
                    var prev = points[i - 1];
                    var current = points[i];
                    var next = points[i];

                    if (i < points.Count - 1)
                        next = points[i + 1];

                    //if (!prev.On && current.On)// && ((prev.Timestamp.AddMinutes(2) < current.Timestamp) || (start == 0)))
                    //{
                    //    start = i;
                    //}



                    if (
                         (prev.Timestamp.AddMinutes(minut) < current.Timestamp))
                    {
                        double max = maxAnt;
                        if (max > prev.FuelLevel || prev.FuelLevel * percLitro > max * percLitro + 20 * percLitro)
                            max = prev.FuelLevel;
                        double min = 1000;
                        if (current.FuelLevel != 0 && current.On)
                            min = current.FuelLevel;
                        for (int l = i; l < points.Count - 2; l++)
                        {
                            if ((points[l].On && prev.On && (points[l].Timestamp.AddMinutes(minut) < points[l + 1].Timestamp || (points[l + 1].Distance < 0.007) || !points[l + 1].On)) || (!points[l].On && points[l + 1].On && points[l].Timestamp.AddSeconds(60) > points[l + 1].Timestamp))
                            {

                                current = points[l + 1];
                                if (points[l].On)
                                {
                                    if (max < current.FuelLevel && current.FuelLevel < maxAnt && current.On)
                                        max = current.FuelLevel;
                                    if (current.FuelLevel < min && current.FuelLevel != 0 && current.On)
                                        min = current.FuelLevel;
                                }
                                i = l + 1;
                            }
                            else
                            {
                                l = points.Count;
                            }
                        }
                        if ((prev.On != current.On && prev.On) || (prev.On && current.On))
                        {
                            Paragem par = new Paragem();
                          //  setAddress(prev);
                            par.Coordinates = prev;
                            par.CoordinatesFim = current;
                            var sec = GetUnixEpoch(current.Timestamp) - GetUnixEpoch(prev.Timestamp);

                            par.duracao = sec;
                            if (i - prevId > 2)
                            {
                                par.Coordinates.FuelLevel = points[prevId + 1].FuelLevel;
                            }

                            int il = i + 1;
                            if (il >= points.Count)
                                il = points.Count - 1;
                            if (!par.CoordinatesFim.On ||
                               (points[il].On && par.CoordinatesFim.On &&
                                par.CoordinatesFim.FuelLevel > points[i - 1].FuelLevel))
                            {
                                current.FuelLevel = points[i - 1].FuelLevel;
                                par.CoordinatesFim.FuelLevel = points[i - 1].FuelLevel;
                            }
                            int l = prevId - 1;
                            if (l < 0)
                                l = prevId;
                            if (par.Coordinates.On && points[l].On && points[prevId + 1].On)
                            {
                                if (par.Coordinates.FuelLevel < points[l].FuelLevel && par.Coordinates.FuelLevel < points[prevId + 1].FuelLevel)
                                {
                                    if (par.Coordinates.Timestamp.AddMinutes(4.5) < points[prevId + 1].Timestamp && par.Coordinates.Timestamp.AddMinutes(5.5) > points[prevId + 1].Timestamp)
                                    {
                                        prev.FuelLevel = points[prevId + 1].FuelLevel;
                                        par.Coordinates.FuelLevel = points[prevId + 1].FuelLevel;
                                    }
                                    else
                                    {
                                        prev.FuelLevel = points[l].FuelLevel;
                                        par.Coordinates.FuelLevel = points[l].FuelLevel;
                                    }
                                }
                            }
                            else
                            {
                                if (par.Coordinates.On && !points[l].On && points[prevId + 1].On && par.Coordinates.Timestamp.AddMinutes(4.5) < points[prevId + 1].Timestamp && par.Coordinates.Timestamp.AddMinutes(5.5) > points[prevId + 1].Timestamp)
                                {
                                    prev.FuelLevel = points[prevId + 1].FuelLevel;
                                    par.Coordinates.FuelLevel = points[prevId + 1].FuelLevel;
                                }
                            }

                            if (par.CoordinatesFim.FuelLevel > par.Coordinates.FuelLevel)
                            {
                                if (points[il].On)
                                {
                                    if ((points[il].FuelLevel > par.Coordinates.FuelLevel && par.CoordinatesFim.FuelLevel > points[il].FuelLevel) || points[il].FuelLevel > par.CoordinatesFim.FuelLevel)
                                    {
                                        par.Coordinates.FuelLevel = par.CoordinatesFim.FuelLevel;
                                        prev.FuelLevel = par.CoordinatesFim.FuelLevel;
                                    }
                                    else
                                    {
                                        par.CoordinatesFim.FuelLevel = par.Coordinates.FuelLevel;
                                        current.FuelLevel = par.Coordinates.FuelLevel;

                                    }
                                }
                                else
                                {
                                    par.CoordinatesFim.FuelLevel = par.Coordinates.FuelLevel;
                                    current.FuelLevel = par.Coordinates.FuelLevel;
                                }
                            }

                            par.Consumo = (par.Coordinates.FuelLevel - par.CoordinatesFim.FuelLevel) * percLitro;
                            //par.Coordinates.FuelLevel = max;
                            //if(par.Coordinates.FuelLevel >= max)
                            //{
                            //    par.Coordinates.FuelLevel = max;
                            //    prev.FuelLevel = max;
                            //}
                            //else
                            //{
                            //    if (par.Coordinates.FuelLevel < maxAnt)
                            //    {
                            //        par.Coordinates.FuelLevel = max;
                            //        prev.FuelLevel = max;
                            //    }
                            //}

                            //if(!par.CoordinatesFim.On)
                            //{
                            //    current.FuelLevel = 0;
                            //    par.CoordinatesFim.FuelLevel = 0;
                            //}
                            //if (prev.FuelLevel == 0 && current.FuelLevel == 0)
                            //    par.Consumo = 0;
                            //else
                            //{
                            //    if (prev.FuelLevel == 0)
                            //    {
                            //        prev.FuelLevel = max;
                            //        par.Coordinates.FuelLevel = max;
                            //    }

                            //    if (current.FuelLevel == 0 && min != 1000)
                            //    {
                            //        current.FuelLevel = min;
                            //        par.CoordinatesFim.FuelLevel = min;
                            //    }
                            //    if (current.FuelLevel == 0)
                            //    {
                            //        current.FuelLevel = next.FuelLevel;
                            //        par.CoordinatesFim.FuelLevel = next.FuelLevel;
                            //    }
                            //    if (current.FuelLevel == 0)
                            //    {
                            //        current.FuelLevel = prev.FuelLevel;
                            //        par.CoordinatesFim.FuelLevel = prev.FuelLevel;
                            //    }
                            //    par.Consumo = (prev.FuelLevel - current.FuelLevel) * percLitro;
                            //    if (par.Consumo < 0)
                            //    {
                            //        par.Consumo = 0;
                            //        par.CoordinatesFim.FuelLevel = par.Coordinates.FuelLevel;
                            //        current.FuelLevel = par.Coordinates.FuelLevel;
                            //    }
                            //}
                            maxAnt = par.CoordinatesFim.FuelLevel;
                            ret.Add(par);
                        }
                    }

                }
            }

            return ret;
        }

        


     

        public static double GetUnixEpoch(DateTime dateTime)
        {
            var unixTime = dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            return unixTime.TotalSeconds;
        }


        public override void Save()
        {
            throw new NotImplementedException();
        }
    }
}